import json
import logging
from functools import wraps
from datetime import datetime
from collections import defaultdict

import pandas as pd

from service.config import NewModelServerConfig
from data_preprocessing.data_processing import DataProcessing
from .catboost_model.training_data import train_main as nonlinear_train


settings = NewModelServerConfig()
# def logging_decorator(func):
#     """
#     打印输出日志修饰器
#     :param func:
#     :return:
#     """
#
#     @wraps(func)
#     def wrapper(request, *args, **kwargs):
#         current_time = datetime.now().strftime('%Y-%m-%d %H:%M:%S')
#         func_name = func.__name__
#         logging.info(f"[{current_time}] Function: {func_name} - Path: {request.META['PATH_INFO']}")
#         json_content = func(request, *args, **kwargs)
#         logging.info(f"[{current_time}] Function: {func_name} - Response: {json_content}")
#         return json.dumps(json_content, ensure_ascii=False)
#
#     return wrapper
#
#
# # ==================== 请求数据处理 ====================
# def get_post_parameters(func):
#     """
#     处理请求携带的参数数据修饰器
#     :param func:
#     :return:
#     """
#
#     @wraps(func)
#     def wrapper(request, *args, **kwargs):
#         if request.method == "GET":
#             return JsonResponse({"status": "fail", "message": "请求方式错误"})
#         else:
#             # 主要对请求参数中为空，为None的数据进行处理
#             data = json.loads(request.body)
#             params_dict = {
#                 "general_parameters": defaultdict(),
#                 "parameters_for_3": defaultdict(),
#                 "parameters_for_28": defaultdict()
#             }
#
#             params_dict['general_parameters'].update(
#                 {
#                     "tenant_id": data['general_parameters'].get("tenantId", "1"),
#                     "start_time": data['general_parameters'].get("startTime", "2023-11-01"),
#                     "end_time": data['general_parameters'].get("endTime", "2025-11-01"),
#                     "model_code_post": data['general_parameters'].get("modelCode", ""),
#                     "product_code_post": data['general_parameters'].get("productCode", "")
#                 }
#             )
#
#             params_dict['parameters_for_3'].update({
#                 "need_combination": data['parameters_for_3'].get("need_combination", True),
#                 "need_chemical": data['parameters_for_3'].get("need_chemical", True),
#                 "need_pca": data['parameters_for_3'].get("need_pca", True),
#                 "need_rfe": data['parameters_for_3'].get("need_RFE", True),
#                 "promotion_rate": data['parameters_for_3'].get("promotion_rate", {"use_1": True, "use_3": False})
#             })
#
#             params_dict['parameters_for_28'].update({
#                 "need_combination": data['parameters_for_28'].get("need_combination", True),
#                 "need_chemical": data['parameters_for_28'].get("need_chemical", True),
#                 "need_pca": data['parameters_for_28'].get("need_pca", True),
#                 "need_rfe": data['parameters_for_28'].get("need_RFE", True),
#                 "promotion_rate": data['parameters_for_28'].get("promotion_rate", {"use_1": True, "use_3": True})
#             })
#         return func(request, params_dict, *args, **kwargs)
#
#     return wrapper



# @logging_decorator
# @get_post_parameters
def cement_train(request, params_dict):
    """
    模型训练接口
    :return:
    """
    # if request.method == "GET":
    #     return {"status": "error", "results": "接口请求方式异常"}

    # need_combination = request.POST.get("need_combination", True)
    # need_chemical = request.POST.get("need_chemical", True)
    # need_pca = request.POST.get("need_pca", True)
    # need_rfe = request.POST.get("need_RFE", True)

    # logging.info("====== 模型训练，租户id：{} ======".format(params_dict['general_parameters']['tenant_id']))
    # prefix_name = settings.self_learning_collection_prefix
    # settings.self_learning_collection_name = prefix_name + str(tenant_id)
    # model_type, mas_model_type = linear_train.get_model_type()  # 获取磨号、水泥品种list
    # db = linear_train.get_db_handle()
    results = []
    # try:
    logging.info("============= 开始读取自学习表 ============")
    # 获取训练数据
    data_aggregator = DataProcessing()
    data_aggregator.read_from_mongo()
    data_aggregator = data_aggregator.process_data()
    # data_aggregator = pd.DataFrame(data_aggregator)
    # 非线性模型训练
    logging.info("============= 非线性模型训练开始 ============")
    model3_n1d, model3_1d, model28_n1d, model28_1d, model28_3d = \
        nonlinear_train_part(data_aggregator, model_name="CatBoost", mas_model_type="CI_10001194",
                             start_time=params_dict['general_parameters']['start_time'],
                             end_time=params_dict['general_parameters']['end_time'],
                             params_for_3d=params_dict['parameters_for_3'],
                             params_for_28d=params_dict['parameters_for_28'])
    results.append({
        'mill_code': mill_code,
        'product_code': product_code,
        'status': 'success',
        'message': '模型训练成功'
    })
    # 循环打包上传到大模型平台上 TODO 如果上线需要将该部分进行打开
    # packaging_and_upload(mas_model_type[i])
    # delete_files_in_directory(settings.save_model_path)
    # 删除所有json文件
    # TODO 上线后该部分代码需要注释掉
    # json_files = glob.glob(os.path.join(settings.save_model_path, "CatBoost", "*.json"))
    # for json_file in json_files:
    #     os.remove(json_file)
    return {'status': 'success', 'results': results}


def nonlinear_train_part(filtered_data: list, model_name: str = "CatBoost", mas_model_type: str = None,
                         start_time: str = "2023-01-01", end_time: str = "2050-01-01", params_for_3d: dict = None,
                         params_for_28d: dict = None):
    """
    非线形模型训练部分
    :param filtered_data:
    :param model_name:
    :param mas_model_type:
    :param start_time:
    :param end_time:
    :param params_for_3d:
    :param params_for_28d:
    :return:
    """
    # 返回的数据类型分别为mse， r2
    model3_n1d, model3_1d, model28_n1d, model28_1d, model28_3d = nonlinear_train(filtered_data,
                                                                                 settings.save_model_path, model_name,
                                                                                 mas_model_type=mas_model_type,
                                                                                 start_time=start_time,
                                                                                 end_time=end_time,
                                                                                 params_for_3d=params_for_3d,
                                                                                 params_for_28d=params_for_28d)
    return model3_n1d, model3_1d, model28_n1d, model28_1d, model28_3d